package test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import main.CachedComputable1;
import main.CachedComputable2;
import main.CachedComputable3;
import main.Computable;
import main.DKUtil;
import main.Factorizator;
import main.Timer;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class Runner {
	private final static int MAX_NUMBER = 128;
	private final static int CYCLES = 1024 * 1024;
	private final static int INTERNAL_CYCLES = 4;

	protected static Computable<Integer, int[]> factorizator;
	protected static ExecutorService executor;
	
	private Timer t = new Timer();

	public void initFactorizator() {
		int[] primes = DKUtil.makeIntArray(DKUtil.generatePrimes(MAX_NUMBER));
		// factorizator = new Factorizator(primes);
		factorizator = new CachedComputable3<>(new Factorizator(primes));
	}

	public Runnable newTask() {
		return new Runnable() {
			public void run() {
				try {
					for (int i = 0; i < INTERNAL_CYCLES; i++) {
						int number = (int) (2 + Math.random()
								* (MAX_NUMBER - 1));
						int[] primes = factorizator.compute(number);
						if (DKUtil.rebuildNumber(primes) == number) {
							; // System.out.println("Ok!");
						} else {
							System.out.println("Error!");
						}
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
	}

	@Before
	public void initExecutor() {
		executor = Executors.newFixedThreadPool(1024);
	}

	@After
	public void checkResults() throws InterruptedException {
		waitFor();
		// assertEquals(CYCLES * INTERNAL_CYCLES, factorizator.getCount());
	}

	@Test
	public void test() {
		initFactorizator();
		t.start();
		for (int i = 0; i < CYCLES; i++) {
			executor.submit(newTask());
		}
	}

	protected void waitFor() throws InterruptedException {
		executor.shutdown();
		boolean terminated = executor.awaitTermination(Long.MAX_VALUE,
				TimeUnit.SECONDS);
		t.printSeconds();
		assertTrue("Finished all tasks.", terminated);
	}
}
